/*
 * Clock.java
 *
 * Created on June 5, 2007, 5:31 PM
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package base;

import tal.drivechain.matchers.VarMatcher;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty;
import tal.drivechain.variable.VarTableAction;
import tal.drivechain.variable.Variable;

/**
 *
 * @author Tal Eisenberg
 */
public class ClockIn extends Module {
    private Variable tempovar = null, statusvar = null;
    private VarTableAction setTempo, setStatus;
    private VarMatcher clockTrigger = null, startTrigger = null, stopTrigger = null;
    private long tempo = -1;
    private long lasttick = -1;
    private int sendCounter = -1;
    private int calcCounter = -1;
    private long duration = -1;
    
    @Override
    public void setupProperties() {
        setStatusVar(props.getProperty("statusVar"), null);
        setTempoVar(props.getProperty("tempoVar"), null);
        setDuration(props.getProperty("duration"), null);
        setClockTrigger(props.getProperty("clockTrigger"), null);
        setStartTrigger(props.getProperty("startTrigger"), null);
        setStopTrigger(props.getProperty("stopTrigger"), null);
        log(tempovar.getName() + " will be updated every " + duration + " ticks.", MSG.DEBUG);
    }

    public void setStatusVar(Object value, SetProperty.Flag flag) {
        if (value==null)
            statusvar = new Variable(this.getName() + ".status", DataType.STRING, null, true);
        else statusvar = (Variable)value;
        setStatus = new VarTableAction(statusvar.getName(), VarTableAction.Action.SET_ANY);
        setStatus.set(statusvar, localVars, this);
    } public Object getStatusVar() { return statusvar; }

    public void setTempoVar(Object value, SetProperty.Flag flag) {
        if (value==null)
            tempovar = new Variable(this.getName() + ".tempo", DataType.STRING, null, true);
        else tempovar = (Variable)value;
        setTempo = new VarTableAction(tempovar.getName(), VarTableAction.Action.SET_ANY);
        setTempo.set(tempovar, getParentChain().getVarTable(), this);
    } public Object getTempoVar() { return tempovar; }

    public void setDuration(Object value, SetProperty.Flag flag) {
        duration = (Long)value;
        if (sendCounter>(duration-1))
            sendCounter=-1;
    } public Object getDuration() { return duration; }
    
    public void setClockTrigger(Object value, SetProperty.Flag flag) {
        clockTrigger = (VarMatcher)value;
    } public Object getClockTrigger() { return clockTrigger; }
    
    public void setStartTrigger(Object value, SetProperty.Flag flag) {
        startTrigger = (VarMatcher)value;
    } public Object getStartTrigger() { return startTrigger; }
    
    public void setStopTrigger(Object value, SetProperty.Flag flag) {
        stopTrigger = (VarMatcher)value;
    } public Object getStopTrigger() { return stopTrigger; }
            
    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        if (clockTrigger.matches(in, channel, this)) {    // received timing clock.
            if (calcCounter==-1 || calcCounter==23) {
                if (lasttick!=-1) {
                    long delta = Math.round((System.nanoTime() - lasttick)/1000000);
                    if (delta>60000) calcCounter=0;
                    if (delta<=0) tempo = -1;
                    else tempo = delta;                    
                } else tempo = -1;
                lasttick = System.nanoTime();
                calcCounter = 0;
            } else calcCounter++;
            if (sendCounter==-1 || sendCounter==duration-1) { // seeing if it should be sent send a message
                if (debugFlag) log("Setting " + tempovar.getName() + "=" + tempo, MSG.DEBUG);
                tempovar.setValue(tempo, true);
                setTempo.set(tempovar, getParentChain().getVarTable(), this);
                if (debugFlag) log("tempo=" + tempovar.getValue(this), MSG.DEBUG);
                sendCounter=0;
            } else sendCounter++;
            
        } else if (startTrigger.matches(in, channel, this)) { // received start message
            statusvar.setValue("play", true);
            setStatus.set(statusvar, getParentChain().getVarTable(), this);
            if (debugFlag) log("Setting " + statusvar.getName() + "=play", MSG.DEBUG);
        } else if (stopTrigger.matches(in, channel, this)) { // received a stop message
            statusvar.setValue("stop", true);
            setStatus.set(statusvar, getParentChain().getVarTable(), this);
            if (debugFlag) log("Setting " + statusvar.getName() + "=stop", MSG.DEBUG);
            tempo = -1;
            lasttick = -1;
            calcCounter = -1;
            sendCounter = -1;
        }
    }
}
